/*
    How does it work:

    Names of exported variables should be defined at first line of module like this::

        // export var_name_one, var_name_two
    
    Then calling of Import(name) returns module object with values bound to these names.

    Import.modules is mapping of qualified module names to modules.

    Known problems:
    
      - Error 404 of file:// protocol doesn't caught in Opera.
    
      - Circular imports:

        Attributes of module from which current module being imported is not
        accessible during import.

      - Relative imports:

        Not implemented by design decision.

*/

function Import(name)
{
    if (Import.modules[name])
        return Import.modules[name]

    var module = Import.modules[name] = new Module, 
        path = Import.__path(name)

    // Script is loaded via XMLHttpRequest instead of "script src" because
    // syncronized execution and comment parsing required.

    var request = new XMLHttpRequest
    request.open('GET', path, false)

    try {
        request.send(null)
    } catch (e) {
        throw new Import.error('No module named ' + name + ' at ' + path)
    }

    if (request.status != (path.substring(0, 7) == 'file://' ? 0 : 200))
        throw new Import.error('Error loading ' + name + ' from ' + path + ' (status ' + request.status + ')')

    var re = /^[ \t]*\/\/[ \t]*export[ \t]+(.+?)[ \t]*[\n\r]/,
        code = request.responseText,
        names = re.exec(code)

    if (! names)
        throw new Import.error(name + ' (' + path + ') is not valid module')

    Import.__pushns()
    Import.__eval('var Import = parent.Import;')

    // executing module code
    Import.__eval(code)

    // constructing module object
    names = names[1].split(/\s*,\s*/)
    for (var i = 0; i < names.length; i++) {
        var vname = names[i]
        try {
            module[vname] = Import.__eval(vname)
        } catch (e) {
            throw new Import.error("Could not import name " + vname + " from module " + name + " (" + path + ")")
        }
    }

    Import.__popns()

    return module
}

Import.modules = {}

Import.__evals = []
Import.__iframes = []
Import.__pushns = function ()
{
    // creating sandbox frame (thanks to Dean Edwards for idea)
    var iframe = document.createElement("iframe"),
        MSIE/*@cc_on =1@*/ // sniff

    iframe.style.display = 'none'
    document.body.appendChild(iframe)
    Import.__iframes[Import.__iframes.length] = iframe

    var frame_win = frames[frames.length - 1]
    if (MSIE) {
        frame_win.document.write('<script><\/script>') // hack to activate Global object
        Import.__evals = [function (s) { return frame_win.eval(s) }].concat(Import.__evals)
    } else {
        frame_win.document.write(
            '<script>' +
            'parent.Import.__evals = [function (s) { return window.eval(s) }].concat(parent.Import.__evals)' +
            '<\/script>'
        )
    }
}

Import.__eval = function (s)
{
    return Import.__evals[0](s)
}

Import.__popns = function ()
{
    var iframe = Import.__iframes[Import.__iframes.length - 1]
    document.body.removeChild(iframe)
    Import.__iframes.length--

    Import.__evals = Import.__evals.slice(1)
}

Import.__path = function (name)
{
    var path = document.location.href

    // foo.bar.baz -> foo/bar/baz.js
    return path.substring(0, path.lastIndexOf('/') + 1) +
           name.replace(/\./g, '/') + '.js'
}

Import.error = function(message)
{
    this.message = message
}
Import.error.prototype.name = 'Import.error'
Import.error.prototype.toString = function()
{
    return this.name + ': ' + this.message
}

function Module() {}
Module.prototype.constructor = Object

if (window.ActiveXObject)
    XMLHttpRequest = function ()
    {
        return new ActiveXObject('Microsoft.XMLHTTP')
    }
